package com.bkbw.live.battle.actor;

import java.security.KeyStore.Entry;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import com.bkbw.live.battle.net.codec.PackageHead;

import akka.actor.Cancellable;
import akka.actor.UntypedActor;
import akka.util.Duration;

import com.bkbw.live.battle.bean.PlayerInDungeon;
import com.bkbw.live.common.dataproto.ClientToBattleServerPb;
import com.bkbw.live.common.dataproto.ClientToBattleServerPb.*;
import com.bkbw.live.battle.net.message.MessageObject;

public class TableActor extends UntypedActor{
	private Cancellable cancel;
	private int tableid;//每个副本的id,这个值和每个用户的联盟id有关系
	//房间中的所有玩家列表
	private Map<Integer,PlayerInDungeon> map = new HashMap<Integer,PlayerInDungeon>();
	
	public TableActor(int tableid) {
		this.tableid = tableid;
		System.out.println("房间"+tableid+"启动");
		update();
	}
	
	@Override
	public void onReceive(Object arg0) throws Exception {
		if("loop".equals(arg0)){
			 update();
		}
		if("stop".equals(arg0)){
			cancel.cancel();
			System.out.println("房间"+tableid+"停止");
		}
		if(arg0 instanceof MessageObject){
			MessageObject mo = (MessageObject) arg0;
			switch (mo.getHead()) {
			case HeadType.DUNGON_LOGIN_REQ_VALUE:
				playerEnter(mo);
				break;
			case HeadType.DUNGON_PLAYER_MOVE_VALUE:	
				playerMove(mo);
				break;
			case HeadType.DUNGON_PLAYER_MOVE_STATE_CHANGE_VALUE:
				playerStateChange(mo);
				break;
			case HeadType.DUNGON_LOGOUT_VALUE:
				playerLogout(mo);
				break;
			default:
				break;
			}
		}
	}
	

	/**
	 * 房间的主循环函数
	 */
	private void update(){
		cancel = this.getContext().system().scheduler().scheduleOnce(Duration.create(50, TimeUnit.MILLISECONDS),getSelf(), "loop");
		//广播每个玩家的位置 
		broadcast();
		//输出每个玩家的位置
		//printPlayerPos();
	}
	
	private void printPlayerPos() {
		// TODO Auto-generated method stub
		String sb = "";
		for(Map.Entry<Integer, PlayerInDungeon> en:map.entrySet()){
			sb+=("id:"+en.getKey()+" state:"+en.getValue().getMoveState()+" pos:"+en.getValue().getPos().getX()+","+en.getValue().getPos().getY()+","+en.getValue().getPos().getZ()+"||");
		}
		System.out.println(sb);
	}

	private void playerEnter(MessageObject mo){
		ClientToBattleServerPb.LoginReq req  = (LoginReq) mo.getData();
		//创建一个玩家对象
		PlayerInDungeon player = new PlayerInDungeon(mo.getSession(),req.getUserId(),req.getName());
		//初始位置，暂时写死
		ClientToBattleServerPb.Vector3d.Builder v3dBuilder = ClientToBattleServerPb.Vector3d.newBuilder();
		v3dBuilder.setX(1);
		v3dBuilder.setY(0);
		v3dBuilder.setZ(1);
		player.setPos(v3dBuilder.build());
		//返回登陆结果
		ClientToBattleServerPb.LoginResp.Builder resBuilder = ClientToBattleServerPb.LoginResp.newBuilder();
		//是否重复连接
		if(map.containsKey(player.getUid())){
			resBuilder.setError(1);//存在错误
			resBuilder.setDescription("uid为"+player.getUid()+"的玩家已经存在");
			return;
		}
		resBuilder.setError(0);//登陆成功
		resBuilder.setDescription("ok");
		
		ClientToBattleServerPb.PlayerInfo.Builder infoBuilder = ClientToBattleServerPb.PlayerInfo.newBuilder();
		infoBuilder.setPos(v3dBuilder.build());
		infoBuilder.setName("name");
		infoBuilder.setId(req.getUserId());
		resBuilder.setSelf(infoBuilder.build());
		
		//组装其他玩家信息
		Iterator<Integer> it = map.keySet().iterator();
		while(it.hasNext()){
			int id = it.next();
			PlayerInDungeon other = map.get(id);
			ClientToBattleServerPb.PlayerInfo.Builder ppb = ClientToBattleServerPb.PlayerInfo.newBuilder();
			ppb.setId(other.getUid());
			ppb.setName(other.getUsername());
			ppb.setPos(other.getPos());
			resBuilder.addOthers(ppb.build());
		}
		//组装地图信息
		for(int i=0;i<5;i++){
			CubeInfo.Builder cb = CubeInfo.newBuilder();
			Vector3d.Builder cbpos = Vector3d.newBuilder();
			cbpos.setX((float) (1.25+i*0.5));
			cbpos.setY(0);
			cbpos.setZ((float) (2.25+i*0.5));
			cb.setPos(cbpos);
			cb.setSize(0.5f);
			resBuilder.addCube(cb);
		}
		
		mo.getSession().write(resBuilder.build());
		//告知房间内的所有玩家这个玩家来了
		Iterator<Integer> it2  = map.keySet().iterator();
		while(it2.hasNext()){
			int id = it2.next();
			PlayerInDungeon p = map.get(id);
			ClientToBattleServerPb.LoginNotify.Builder builder = ClientToBattleServerPb.LoginNotify.newBuilder();
			ClientToBattleServerPb.PlayerInfo.Builder infobuilder = ClientToBattleServerPb.PlayerInfo.newBuilder();
			infobuilder.setId(req.getUserId());
			infobuilder.setName(req.getName());
			infobuilder.setPos(v3dBuilder.build());
			builder.setInfo(infobuilder.build());
			p.getSession().write(builder.build());
		}
		//保存到房间数组中 
		map.put(req.getUserId(), player);
	}
	
	//玩家状态改变
	private void playerStateChange(MessageObject mo) {
		MoveStateChange m = (MoveStateChange) mo.getData();
		if(map.containsKey(m.getId())){
			map.get(m.getId()).setMoveState(m.getState());
			System.out.println("玩家"+m.getId()+"状态改变为"+m.getState());
			broadcastToAll();
		}
	}
	//处理玩家移动仅仅更新当前玩家位置
	private void playerMove(MessageObject mo){
		ClientToBattleServerPb.Move mov  = (Move) mo.getData();

		if(map.containsKey(mov.getId())){
			map.get(mov.getId()).setPos(mov.getPos());

		}
	}
	
	//处理玩家登出
	private void playerLogout(MessageObject mo){
		ClientToBattleServerPb.Logout req  = (Logout) mo.getData();
		//从房间数组移除
		map.remove(req.getUserId());
		//告知房间内的所有玩家这个玩家走了
		Iterator<Integer> it = map.keySet().iterator();
		while(it.hasNext()){
			int id = it.next();
			PlayerInDungeon p = map.get(id);
			ClientToBattleServerPb.LogoutNotify.Builder builder = ClientToBattleServerPb.LogoutNotify.newBuilder();
			builder.setId(req.getUserId());
			p.getSession().write(builder.build());
		}
	}
	
	/**
	 * 给客户端发广播，广播的一个基本准则是这样
	 * 如果A在移动，那么一定会把A周围的玩家广播给A（哪怕这些玩家没动，否则A如果靠近一个没动的B就看不见B了）
	 * 如果A没有移动，那么只会把A周围正在移动的玩家广播给A
	 * 对于每一个玩家，都作上述处理
	 * 
	 * 广播的内容包括
	 * 1.id
	 * 2.位置
	 * 3.状态
	 * 如果客户端收到的状态为1，则将此玩家移动到位置，如果收到的状态为0，则把此玩家setPosition()到此位置
	 * 
	 * 状态和位置由客户端不断的向服务器请求后在服务器端保存
	 */
	private void broadcast(){
		Iterator<Integer> it = map.keySet().iterator();
		while(it.hasNext()){
			int id = it.next();
			PlayerInDungeon player = map.get(id);
			//组装一条需要发给某个玩家的广播信息
			MoveNotify mn = null;
			if(player.getMoveState()==0){
				mn = getNearPlayer(player,map.keySet().iterator(),true);
			}else{
				mn = getNearPlayer(player,map.keySet().iterator(),false);
			}
			if(mn.getListCount()>0){
				player.getSession().write(mn);
			}
		}
	}
	private void broadcastToAll(){
		Iterator<Integer> it = map.keySet().iterator();
		while(it.hasNext()){
			int id = it.next();
			PlayerInDungeon player = map.get(id);
			//组装一条需要发给某个玩家的广播信息
			MoveNotify mn = getNearPlayer(player,map.keySet().iterator(),false);
			if(mn.getListCount()>0){
				player.getSession().write(mn);
			}
		}
	}
	
	/**
	 * 获取一个玩家周围的其他玩家信息
	 * @param player
	 * @param list
	 * @param includeIdel是否忽略站立不动的玩家
	 */
	private MoveNotify getNearPlayer(PlayerInDungeon player,Iterator<Integer> it,boolean ignorIdle){
		MoveNotify.Builder mb = MoveNotify.newBuilder();
		while(it.hasNext()){
			int id = it.next();
			PlayerInDungeon other = map.get(id);
			if(other.getUid()!=player.getUid()){
				//如果不包含静止的，就要忽略静止的
				if(ignorIdle&&other.getMoveState()==0){
					continue;
				}
				MoveDataPb.Builder pmd = MoveDataPb.newBuilder();
				pmd.setId(other.getUid());
				pmd.setPos(other.getPos());
				pmd.setState(other.getMoveState());
				mb.addList(pmd.build());
			}
		}
		return mb.build();
	}
}
